package com.sophialex.health.record.common.bind.swt.annotations;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;

import org.eclipse.core.databinding.Binding;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.core.databinding.beans.BeansObservables;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.part.ViewPart;

import com.sophialex.health.record.common.bind.swt.annotations.helper.BuildinBindHelper;

public class BindToProcesspor extends AbstractBindingProcessor {

	protected DataBindingContext bindingContext;
	protected BuildinBindHelper helper;
	public BindToProcesspor(ViewPart view, Field f, AnnotionProcessor parent, DataBindingContext bindingContext) {
		super(view, f, parent);
		this.bindingContext = bindingContext;
		helper = BuildinBindHelper.getInstance(f);
	}

	
	protected Object observeBean(boolean multiValue) {
		// 映射bean
		Object o = null;
		Object bean = getBindingBean();
		String path = getBindingBeanPath();
		String prePath = helper.getBeanPath().substring(0, helper.getBeanPath().lastIndexOf(path)-1);
		if (!multiValue) {
			o = BeansObservables.observeValue(bean, path);
			parent
			.out("      modelElement = BeansObservables.observeValue("+prePath+","
					+ path + ");\r\n");
		}else{
			o = BeansObservables.observeList(bean, path);
			parent
			.out("      modelElement = BeansObservables.observeList("+prePath+","
					+ path + ");\r\n");
		}
		return o;

	}

	protected Object getBindingBean() {
		if (helper.getBeanPath().split("\\.").length == 1) {
			return view;
		}else{
			String beanName = helper.getBeanPath().split("\\.")[0];
			//Field beanField = null;
			Field beanField = null;
			List<Field> fs = getFields(view.getClass(), true);
			for(Field f:fs){
				if(f.getName().equals(beanName))
					beanField = f;
			}
			if(beanField == null)
				throw new BadBindingException("beanPath设置有误:"
						+ view.getClass().getSimpleName() + "不存在名为'" + beanName
						+ "'的字段！");
			beanField.setAccessible(true);
			Object result = null;
			try {
				result = beanField.get(view);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} 
			return result;
		}
		
	}
	protected String getBindingBeanPath() {
		if (helper.getBeanPath().split("\\.").length == 1) {
			return helper.getBeanPath();
		}else{
			String beanName = helper.getBeanPath().split("\\.")[0];
			return helper.getBeanPath().replaceFirst(beanName + ".", "");
		}
	}
	protected void vadidateAnnotation() {
		BindTo ba = f.getAnnotation(BindTo.class);
		if (helper.getUIPropName() == null || helper.getUIPropName().trim().length() < 1)
			throw new BadBindingException(ba + "的属性UIPropName不能为空");
		if (helper.getBeanPath() == null || helper.getBeanPath().trim().length() < 1)
			throw new BadBindingException(ba + "的属性beanPath不能为空");
	}

	// 获得SWTObservables.observeXX（）所对应的Method
	private Method getObserveMethod(Field f) {
		String UIProp = helper.getUIPropName();
		String MethodName = "observe"
				+ Character.toUpperCase(UIProp.charAt(0))
				+ UIProp.substring(1);
		try {
			Method m = SWTObservables.class.getMethod(MethodName,
					Control.class, int.class);
			return m;
		} catch (SecurityException e) {
			e.printStackTrace();
			//System.exit(-1);
		} catch (NoSuchMethodException e) {
			try {
				Method m = SWTObservables.class.getMethod(MethodName,
						Control.class);
				return m;
			} catch (Exception e1) {
				e1.printStackTrace();
			}
			parent.out("字段"
					+ view.getClass().getSimpleName() + "." + f.getName()
					+ "上的注解的UIPropName设置有误");
		}
		return null;// 鸟东西，根本走不到这非让我加这条语句，不然就报错！

	}
	

	@Override
	protected void bind() {
		// 得到用于绑定SWT部件的SWTObservables.observeXX()方法
		Method m = getObserveMethod(f);

		parent.out("--->" + helper.getBeanPath() + "["
				+ lastElementType.getSimpleName() + "]:\r\n");
		parent.out("   Annotation:"
				+ helper.toString().substring(helper.toString().indexOf(".BindTo") + 1)
				+ "\r\n");
		parent.out("   Binding Details:\r\n    {\r\n");
		Class<?>[] paramTypes = m.getParameterTypes();
		Control ctl = getControl(f);

		
		IObservableValue uiElement = null;
		IObservableValue modelElement = null;
		IObservableList uiList = null;
		IObservableList modelList = null;

		Object[] args = null;

		// 定义控件observeXX方法的参数
		if (paramTypes.length == 2) {
			args = new Object[] { ctl, SWT.Modify };// BindWithTwoArgs(f, m,
			// ba);
		} else {
			args = new Object[] { ctl };
		}

		// 绑定控件
		Object o = null;
		try {
			o = m.invoke(SWTObservables.class, args);
		} catch (Exception e) {
			new BadBindingException("observeXX调用失败，原因可能为UIPropName属性设置错误", e);
			e.printStackTrace();
			//System.exit(-1);
		}

		// 根据返回值类型的不同赋值
		if (IObservableValue.class.isAssignableFrom(o.getClass())) {
			uiElement = (IObservableValue) o;
			parent.out("      uiElement = SWTObservables." + m.getName() + "("
					+ f.getName() + ");\r\n");

		} else {
			uiList = (IObservableList) o;
			parent.out("      uiList = SWTObservables." + m.getName() + "("
					+ f.getName() + ");\r\n");
		}

		// 绑定bean
		if (uiElement != null) {

			// 控件单值而bean属性多值
			if (Collection.class.isAssignableFrom(lastElementType)) {
				throw new BadBindingException("控制属性与bean属性类型不匹配!");
			}
			modelElement = (IObservableValue) observeBean(false);
		} else {
			// 控件多值而bean属性单值
			if (!Collection.class.isAssignableFrom(lastElementType)) {
				throw new BadBindingException("控制属性与bean属性类型不匹配!");
			}
			modelList = (IObservableList) observeBean(true);
		}

		UpdateValueStrategy targetToModel = parent.toModelInstanceFor(f
				.getName());

		UpdateValueStrategy modelToTarget = parent.toTargetInstanceFor(f
				.getName());

		Binding bind = null;
		// 绑定
		if (uiElement != null) {
			bind = bindingContext.bindValue(uiElement, modelElement, targetToModel,
					modelToTarget);
			parent
					.out("      bindingContext.bindValue(uiElement, modelElement, "
							+ targetToModel
							+ ", "
							+ modelToTarget
							+ ");\r\n    }\r\n");
		}
		if (uiList != null) {
			bind = bindingContext.bindList(uiList, modelList);
			parent
					.out("      bindingContext.bindList(uiList, modelList);\r\n    }\r\n");
		}
		//bind.updateTargetToModel();
		parent.addBinding(f.getName(), bind);
		
	}


	@Override
	protected String getBeanPath() {
		return helper.getBeanPath();
	}


	
}